package com.mengyan.manage.cms.service.Impl;


import com.mengyan.framework.domain.cms.CmsConfig;
import com.mengyan.framework.domain.cms.CmsPage;
import com.mengyan.framework.domain.cms.CmsTemplate;
import com.mengyan.framework.domain.cms.request.QueryPageRequest;
import com.mengyan.framework.domain.cms.response.CmsCode;
import com.mengyan.framework.domain.cms.response.CmsPageResult;
import com.mengyan.framework.exception.CustomException;
import com.mengyan.framework.exception.ExceptionCast;
import com.mengyan.framework.model.response.CommonCode;
import com.mengyan.framework.model.response.QueryResponseResult;
import com.mengyan.framework.model.response.QueryResult;
import com.mengyan.framework.model.response.ResponseResult;
import com.mengyan.manage.cms.dao.CmsConfigRepository;
import com.mengyan.manage.cms.dao.CmsPageRepository;
import com.mengyan.manage.cms.dao.CmsTemplateRepository;
import com.mengyan.manage.cms.service.PageService;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Map;
import java.util.Optional;

@Service
public class PageServiceImpl implements PageService {

    @Autowired
    private CmsPageRepository cmsPageRepository;

    @Autowired
    private CmsConfigRepository cmsConfigRepository;

    @Autowired
    private CmsTemplateRepository cmsTemplateRepository;

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private GridFSBucket gridFSBucket;

    @Autowired
    private RestTemplate restTemplate;
    @Override
    public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest) {
        if( queryPageRequest == null) {
            queryPageRequest = new QueryPageRequest();
        }
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withMatcher("pageAliase",ExampleMatcher.GenericPropertyMatchers.contains());
        CmsPage cmsPage = new CmsPage();
        //BeanUtils.copyProperties(queryPageRequest,cmsPage);

        if(StringUtils.isNotEmpty(queryPageRequest.getSiteId())) {
            cmsPage.setSiteId(queryPageRequest.getSiteId());
        }
        if(StringUtils.isNotEmpty(queryPageRequest.getTemplateId())) {
            cmsPage.setTemplateId(queryPageRequest.getTemplateId());
        }
        if(StringUtils.isNotEmpty(queryPageRequest.getPageAliase())) {
            cmsPage.setPageAliase(queryPageRequest.getPageAliase());
        }

        Example<CmsPage> example = Example.of(cmsPage,exampleMatcher);
        if(page < 1) {
            page = 1;
        }
        Pageable pageable = PageRequest.of(page-1,size);
        Page<CmsPage> pages = cmsPageRepository.findAll(example,pageable);
        QueryResult queryResult = new QueryResult();
        queryResult.setList(pages.getContent());
        queryResult.setTotal(pages.getTotalElements());
        QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS,queryResult);
        return queryResponseResult;
    }

    @Override
    public CmsPageResult add(CmsPage cmsPage) {
        //校验页面名称、站点id、页面webpath唯一性
        Optional<CmsPage> byPageNameAndSiteIdAndPageWebPath = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
        if(!byPageNameAndSiteIdAndPageWebPath.isPresent()) {
            cmsPage.setPageId(null);
            CmsPage page =cmsPageRepository.save(cmsPage);
            return new CmsPageResult(CommonCode.SUCCESS,cmsPage);
        } else {
            ExceptionCast.cast(CmsCode.CMS_ADDPAGE_EXISTSNAME);
           // throw new CustomException(CommonCode.FAIL);
        }
        return new CmsPageResult(CmsCode.CMS_ADDPAGE_EXISTSNAME,null).setMessage("页面名称、站点id、页面webpath已存在");
    }

    @Override
    public CmsPageResult getById(String id) {
        Optional<CmsPage> byId = cmsPageRepository.findById(id);
        if(byId.isPresent()) {
            CmsPage cmsPage = byId.get();
            return new CmsPageResult(CommonCode.SUCCESS,cmsPage);
        }
        return new CmsPageResult(CommonCode.FAIL,null).setMessage("没有查询到相关数据");
    }

    @Override
    public CmsPageResult update(String id, CmsPage cmsPage) {
        Optional<CmsPage> byId = cmsPageRepository.findById(id);
        if(byId.isPresent()) {
            //在修改时添加页面名称、站点id、页面webpath校验
            /*
            Optional<CmsPage> byPageNameAndSiteIdAndPageWebPath = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
            if(byPageNameAndSiteIdAndPageWebPath.isPresent()) {
                return new CmsPageResult(CommonCode.FAIL,null).setMessage("页面名称、站点id、页面webpath已存在");
            }
            */
            CmsPage page = byId.get();
            page.setTemplateId(cmsPage.getTemplateId());
            page.setSiteId(cmsPage.getSiteId());
            page.setPageAliase(cmsPage.getPageAliase());
            page.setPageName(cmsPage.getPageName());
            page.setPageWebPath(cmsPage.getPageWebPath());
            page.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
            page.setDataUrl(cmsPage.getDataUrl());
            cmsPageRepository.save(page);
            return new CmsPageResult(CommonCode.SUCCESS,page);
        }
        return  new CmsPageResult(CommonCode.FAIL,null);
    }

    @Override
    public ResponseResult delete(String id) {
        Optional<CmsPage> byId = cmsPageRepository.findById(id);

        if(byId.isPresent()) {
            cmsPageRepository.deleteById(id);
            return new ResponseResult(CommonCode.SUCCESS);
        }

        return new ResponseResult(CommonCode.FAIL).setMessage("没有找到对应页面");
    }

    @Override
    public CmsConfig getConfigById(String id) {

        Optional<CmsConfig> optional = cmsConfigRepository.findById(id);
        if(optional.isPresent()) {
            CmsConfig cmsConfig = optional.get();
            return cmsConfig;
        }
        return null;
    }

    //优化过
    @Override
    public String getPageHtml(String pageId) {
        //取出页面的信息
        Optional<CmsPage> byId = cmsPageRepository.findById(pageId);
        if(byId.isPresent()) {
            CmsPage cmsPage = byId.get();
            //获取数据模型
            Map model = getModelByPageId(cmsPage);
            if(model == null) {
                //数据模型获取不到
                ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
            }
            //获取模板内容
            String templateByPageId = getTemplateByPageId(cmsPage);
            if(StringUtils.isEmpty(templateByPageId)) {
                ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
            }
            //执行静态化
            String html = generateHtml(templateByPageId, model);
            return html;

        } else {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }

        return null;
    }

    //页面静态化
    private String generateHtml(String template, Map model) {
        //创建配置对象
        Configuration configuration = new Configuration(Configuration.getVersion());
        //创建模板加载器
        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
        stringTemplateLoader.putTemplate("template",template);
        //向configuration配置模板加载器
        configuration.setTemplateLoader(stringTemplateLoader);
        //获取模板
        try {
            Template template1 = configuration.getTemplate("template");
            //调用API进行静态化
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template1, model);
            return content;
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException(CommonCode.FAIL);
        }
    }

    //获取页面模板信息
    private String getTemplateByPageId(CmsPage cmsPage) {
        //获取页面模板id
        String templateId = cmsPage.getTemplateId();
        if(StringUtils.isEmpty(templateId)) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        //查询模板信息
        Optional<CmsTemplate> optional = cmsTemplateRepository.findById(templateId);
        if(optional.isPresent()) {
            CmsTemplate cmsTemplate = optional.get();
            String templateFileId = cmsTemplate.getTemplateFileId();
            GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));

            //
            GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
            GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);

            try {
                String context = IOUtils.toString(gridFsResource.getInputStream(), "utf-8");
                return context;
            } catch (IOException e) {
                e.printStackTrace();
                throw new CustomException(CommonCode.FAIL);
            }
        }

        return null;
    }

    //获取数据模型
    private Map getModelByPageId(CmsPage cmsPage) {
            String dataUrl = cmsPage.getDataUrl();
            if(StringUtils.isEmpty(dataUrl)) {
                //页面dataUrl为空
                ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
            }
            ResponseEntity<Map> forEntity = restTemplate.getForEntity(dataUrl, Map.class);
            Map body = forEntity.getBody();
            return body;
    }
}
